package com.pmpd.activity.aop;

import com.dmap.base.constants.Constant;
import com.dmap.base.vo.BaseVo;
import com.pmpd.activity.annotation.LimitRequest;
import com.pmpd.activity.cache.LimitRequestCacheDao;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * \* User: silent
 * \* Date: 12/01/18 Time: 18:28
 * \* Description:
 * \
 */
@SuppressWarnings("Duplicates")
@Aspect
@Component
public class LimitIPRequestDisplay {
    private static final Logger logger = LoggerFactory.getLogger(LimitIPRequestDisplay.class);

    @Resource
    private LimitRequestCacheDao limitRequestCacheDao;

    @Pointcut("execution(* com.pmpd.activity.controller.api.*.*(..))&& @annotation(com.pmpd.activity.annotation.LimitRequest))")
    public void limit() {
    }

    @Around("limit()")
    public BaseVo requestLimit(ProceedingJoinPoint joinPoint) throws Exception {
        BaseVo baseVo = new BaseVo();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String url = request.getRequestURI();
        String userString = request.getHeader("userId");
        Integer count = limitRequestCacheDao.selectLimitRequestCache(url, userString);

        LimitRequest limit = this.getAnnotation(joinPoint);
        if (limit == null) {
            baseVo.setCode(Constant.RESPONSE_SYSTEM_EXCEPTION_ERROR_CODE);
            baseVo.setMsg(Constant.RESPONSE_SYSTEM_EXCEPTION_ERROR_MSG);
            return baseVo;
        }
        if (count > limit.limitCounts()) {
            baseVo.setCode(Constant.RESPONSE_FREQUENT_REQUEST_ERROR_CODE);
            baseVo.setMsg(Constant.RESPONSE_FREQUENT_REQUEST_ERROR_MSG);
            return baseVo;
        }
        limitRequestCacheDao.insertAndUpdateLimitRequestCache(count + 1, url, userString, limit.timeSecond());
        try {
            baseVo = (BaseVo) joinPoint.proceed();
        } catch (Throwable throwable) {
            logger.error("limit error:{}", throwable.getCause());
        }
        return baseVo;
    }


    private LimitRequest getAnnotation(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(LimitRequest.class);
        }
        return null;
    }


}
